knitr::opts_chunk$set(warning=FALSE, message=FALSE)
options(scipen=0, digits=4)

Introduction

Below are code and outputs for the ROI-based analyses in the submitted manuscript: “Neural substrates for moral judgments of psychological versus physical harm”.

To see larger versions of any figure, right-click, copy image location, and paste the address to a new tab on your browser.

If you have any questions and/or comments, please email Lily Tsoi: lily [dot] tsoi [at] bc [dot] edu.

Packages

Install packages and load libraries

packages <- c("rmarkdown", "knitr", "tidyverse", "broom", "lme4", "ordinal", "lsmeans")
packages_new <- packages[!(packages %in% installed.packages()[,"Package"])]
if(length(packages_new)) install.packages(packages_new)
lapply(packages,library,character.only=T)

Data import

Data files can be found on GitHub: https://github.com/tsoices/psych-phys-harm

Analyses require the following files:

  • PSYCH-PHYS_ROI_PSCs.csv
  • ROI_mvpa_results.csv

Make sure these files are in the same directory.

files <- c("ROI_PSCs.csv", "ROI_MVPA.csv")
dat_names <- c("dat_psc_orig", "dat_mvpa_orig")
for(i in 1:length(files)) {
  assign(dat_names[i], read.csv(paste(params$directory, files[i], sep='/')))
}
# change the order of levels
dat_psc_orig$Group <- factor(dat_psc_orig$Group, levels=c("NT", "ASD"))
dat_psc_orig$Violation <- factor(dat_psc_orig$Violation, levels=c("PH", "PS", "N"))

Analyses are based on the following:

  • Number of NT participants: 25
  • Number of ASD participants: 16
  • Number of total participants: 41

Behavioral results

Examining behavioral responses in the scanner

  • DV: rating (1-4)
  • predictors: Condition (physical, psychological, neutral), Group (NT, ASD)

Data organization

Organize behavioral data

# calculate mean rating as variable on y-axis
dat_behav <- dat_psc_orig%>%
  filter(Violation == 'PH' | Violation == 'PS' | Violation == 'N') %>%
  group_by(Subject, Violation, Group, Item, Key) %>%
  summarise(mean=mean(Key)) %>%
  droplevels.data.frame(.)
dat_behav$Item <- match(dat_behav$Item, unique(sort(dat_behav$Item))) # ordering items such that it doesn't care about purity items

Ratings by condition and group

ggplot(dat_behav, aes(x=Violation, y=mean, color=Violation)) +
  stat_summary(fun.data="mean_cl_boot", position=position_dodge(0.2), size=1) +
  ylim(1,4) +
  facet_wrap(~Group, ncol=2, labeller=labeller(Group=c(NT="Neurotypical", ASD="ASD")), scales="free_y") +
  scale_x_discrete(labels=c('Physical','Psychological', 'Neutral')) +
  scale_colour_manual(name="Condition", labels=c("Physical", "Psychological", "Neutral"), values=c("red", "darkorchid4", "slategray")) +
  ylab("Rating\n(1=not at all, 4=very)") +
  xlab("Condition") +
  theme_bw() +
  theme(axis.text=element_text(size=12),
        axis.title=element_text(size=16,face="bold"),
        axis.title.y=element_text(margin=margin(r=18)),
        axis.title.x=element_text(margin=margin(t=18)),
        plot.title=element_text(size=18,face="bold", margin=margin(b=20), hjust=0.5),
        legend.text=element_text(size=14),
        legend.title=element_text(size=14,face="bold"),
        strip.text=element_text(size=14),
        panel.grid.major.x=element_blank(),
        panel.grid.major.y=element_blank())

Ratings by item and group

ggplot(dat_behav, aes(y=mean, x=Item, color=Violation)) +
  stat_summary(fun.data="mean_cl_boot", na.rm=TRUE) +
  ylim(1,4) +
  facet_wrap(~Group, ncol=2, labeller=labeller(Group=c(NT="Neurotypical", ASD="ASD")), scales="free_y") +
  scale_colour_manual(name="Condition", labels=c("Physical", "Psychological", "Neutral"), values=c("red", "darkorchid4", "slategray")) +
  ylab("Rating\n(1=not at all, 4=very)") +
  xlab("Item") +
  theme_bw() +
  theme(axis.text=element_text(size=12),
        axis.title=element_text(size=16,face="bold"),
        axis.title.y=element_text(margin=margin(r=18)),
        axis.title.x=element_text(margin=margin(t=18)),
        plot.title=element_text(size=18,face="bold", margin=margin(b=20), hjust=0.5),
        legend.text=element_text(size=14),
        legend.title=element_text(size=14,face="bold"),
        strip.text=element_text(size=14),
        panel.grid.major.x=element_blank(),
        panel.grid.major.y=element_blank())

Analyses

Define the model

dat_behav$Key <- factor(dat_behav$Key)
model_behav <- clmm(Key ~ Violation*Group + (1|Subject) + (1|Item), 
                    data=dat_behav,
                    link="probit",
                    na.action=na.omit)

Test interaction between Group and Condition

anova(model_behav, update(model_behav, . ~ . -Violation:Group))
Likelihood ratio tests of cumulative link models:
 
                                             formula:                                             link:  threshold:
update(model_behav, . ~ . - Violation:Group) Key ~ Violation + Group + (1 | Subject) + (1 | Item) probit flexible  
model_behav                                  Key ~ Violation * Group + (1 | Subject) + (1 | Item) probit flexible  

                                             no.par  AIC logLik LR.stat df Pr(>Chisq)
update(model_behav, . ~ . - Violation:Group)      9 2443  -1213                      
model_behav                                      11 2445  -1212    2.07  2       0.36

Test main effect of condition

anova(update(model_behav, . ~ . - Violation:Group), update(model_behav, . ~ . - Violation:Group - Violation))
Likelihood ratio tests of cumulative link models:
 
                                                         formula:                                             link:  threshold:
update(model_behav, . ~ . - Violation:Group - Violation) Key ~ Group + (1 | Subject) + (1 | Item)             probit flexible  
update(model_behav, . ~ . - Violation:Group)             Key ~ Violation + Group + (1 | Subject) + (1 | Item) probit flexible  

                                                         no.par  AIC logLik LR.stat df Pr(>Chisq)    
update(model_behav, . ~ . - Violation:Group - Violation)      7 2515  -1251                          
update(model_behav, . ~ . - Violation:Group)                  9 2443  -1213      76  2     <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
lsmeans(model_behav, pairwise ~ Violation)
NOTE: Results may be misleading due to involvement in interactions
$lsmeans
 Violation  lsmean     SE df asymp.LCL asymp.UCL
 PH         1.0778 0.1362 NA    0.8108    1.3448
 PS         0.7947 0.1350 NA    0.5300    1.0594
 N         -0.9417 0.1421 NA   -1.2203   -0.6631

Results are averaged over the levels of: Group 
Confidence level used: 0.95 

$contrasts
 contrast estimate     SE df z.ratio p.value
 PH - PS    0.2831 0.1347 NA   2.102  0.0895
 PH - N     2.0195 0.1534 NA  13.163  <.0001
 PS - N     1.7364 0.1519 NA  11.432  <.0001

Results are averaged over the levels of: Group 
P value adjustment: tukey method for comparing a family of 3 estimates 

ROI-based univariate results

Data organization

Analyses described here are over the entire time course. Future versions of this document will let you select a time window and automatically refresh the outputs related to that time window.

Time points of interest (seconds):

  • entire time course: 6-26
  • background: 6-10
  • action: 12-14
  • outcome: 16-18
  • intent: 20-22
  • judgment: 24-26
time_entire <- dat_psc_orig %>% filter(Timepoint >= 6 & Timepoint <= 26)
time_background <- dat_psc_orig %>% filter(Timepoint >= 6 & Timepoint <= 10)
time_action <- dat_psc_orig %>% filter(Timepoint >= 12 & Timepoint <= 14)
time_outcome <- dat_psc_orig %>% filter(Timepoint >= 16 & Timepoint <= 18)
time_intent <- dat_psc_orig %>% filter(Timepoint >= 20 & Timepoint <= 22)
time_judgment <- dat_psc_orig %>% filter(Timepoint >= 24 & Timepoint <= 26)
dat_psc_long <- 
  time_entire %>% 
  filter(Violation == 'PH' | Violation == 'PS' | Violation == 'N') %>%
  group_by(Subject, Violation, ROI, Group, Item, Key) %>%
  summarise(PSC=mean(PSC)) %>%
  droplevels.data.frame(.)
dat_psc_long$Item <- as.factor(dat_psc_long$Item)

NT

Subset data to NT group only and define model

data_nt <- subset(dat_psc_long, Group == "NT")
model_nt <- lmer(PSC ~ 
                   Violation*ROI +
                   (1|Subject) + (1|Item), data=data_nt, REML=FALSE)
model_nt_1 <- lmer(PSC ~ 
                     Violation*ROI +
                     (Violation|Subject) + (1|Item), data=data_nt, REML=FALSE)

Test the condition x ROI interaction

anova(model_nt, update(model_nt, . ~ . - Violation:ROI))
Data: data_nt
Models:
update(model_nt, . ~ . - Violation:ROI): PSC ~ Violation + ROI + (1 | Subject) + (1 | Item)
model_nt: PSC ~ Violation * ROI + (1 | Subject) + (1 | Item)
                                        Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_nt, . ~ . - Violation:ROI)  9 5907 5961  -2945     5889                        
model_nt                                15 5918 6009  -2944     5888  0.96      6       0.99

Test the main effect of condition

anova(update(model_nt, . ~ . - Violation:ROI), update(model_nt, . ~ . - Violation:ROI - Violation))
Data: data_nt
Models:
update(model_nt, . ~ . - Violation:ROI - Violation): PSC ~ ROI + (1 | Subject) + (1 | Item)
update(model_nt, . ~ . - Violation:ROI): PSC ~ Violation + ROI + (1 | Subject) + (1 | Item)
                                                    Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)  
update(model_nt, . ~ . - Violation:ROI - Violation)  7 5911 5954  -2949     5897                          
update(model_nt, . ~ . - Violation:ROI)              9 5907 5961  -2945     5889  8.42      2      0.015 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# test pairwise contrasts
lsmeans(model_nt, pairwise ~ Violation)
Loading required namespace: lmerTest
NOTE: Results may be misleading due to involvement in interactions
$lsmeans
 Violation  lsmean      SE    df lower.CL upper.CL
 PH        0.11599 0.03906 52.59  0.03764   0.1943
 PS        0.15406 0.03906 52.59  0.07571   0.2324
 N         0.02426 0.03906 52.59 -0.05409   0.1026

Results are averaged over the levels of: ROI 
Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE    df t.ratio p.value
 PH - PS  -0.03807 0.04356 36.89  -0.874  0.6600
 PH - N    0.09173 0.04356 36.89   2.106  0.1025
 PS - N    0.12980 0.04356 36.89   2.979  0.0138

Results are averaged over the levels of: ROI 
P value adjustment: tukey method for comparing a family of 3 estimates 

Test whether including random slope of condition improves model

anova(model_nt, model_nt_1)
Data: data_nt
Models:
model_nt: PSC ~ Violation * ROI + (1 | Subject) + (1 | Item)
model_nt_1: PSC ~ Violation * ROI + (Violation | Subject) + (1 | Item)
           Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
model_nt   15 5918 6009  -2944     5888                        
model_nt_1 20 5928 6048  -2944     5888  0.55      5       0.99

Figure: time course for each condition by ROI

dat_psc_orig$ROI <- factor(dat_psc_orig$ROI, levels=c("RTPJ", "LTPJ", "PC", "DMPFC"))
dat_psc_orig$Violation <- factor(dat_psc_orig$Violation, levels=c("PS", "PH", "N"))
dat_psc_nt <- dat_psc_orig%>% 
  filter(Group == 'NT' & (Violation == 'PH' | Violation == 'PS' | Violation == 'N')) %>%
  group_by(Subject, Violation, ROI, Timepoint) %>%
  summarise(PSC=mean(PSC))
cols <- c("PS"="darkorchid4", "PH"="red", "N"="slategray")
rois <- c(RTPJ="rTPJ", LTPJ="lTPJ", PC="precuneus", DMPFC="dmPFC")
ggplot(dat_psc_nt, aes(y=PSC, x=Timepoint, color=Violation, fill=Violation)) +
  geom_smooth(na.rm=TRUE) +
  facet_wrap(~ROI, ncol=4, labeller=labeller(ROI=rois)) +
  annotate("rect", xmin=5, xmax=27, ymin=-Inf, ymax=Inf, alpha=.1) +
  scale_x_continuous(limits=c(0,28), breaks=seq(0,28,2)) +
  ylab("Percent signal change (PSC)") +
  xlab("Timepoint (s)") +
  scale_fill_manual(name="Condition\n", labels=c("Psychological harm", "Physical harm", "Neutral act"), values=cols) +
  scale_colour_manual(name="Condition\n", labels=c("Psychological harm", "Physical harm", "Neutral act"), values=cols) +
  theme_bw() +
  theme(axis.text=element_text(size=16),
        axis.title=element_text(size=24,face="bold"),
        axis.title.y=element_text(margin=margin(r=20)),
        axis.title.x=element_text(margin=margin(t=20)),
        legend.text=element_text(size=20),
        legend.title=element_text(size=24,face="bold"),
        legend.key.size=unit(3, "lines"),
        strip.text=element_text(size=28, face="bold"),
        panel.grid.major.x=element_blank(),
        panel.grid.major.y=element_blank())

Subset data by ROI (NT only) and define models

dat_rtpj_nt <- subset(dat_psc_long, ROI == "RTPJ" & Group == "NT")
dat_ltpj_nt <- subset(dat_psc_long, ROI == "LTPJ" & Group == "NT")
dat_pc_nt <- subset(dat_psc_long, ROI == "PC" & Group == "NT")
dat_dmpfc_nt <- subset(dat_psc_long, ROI == "DMPFC" & Group == "NT")
model_rtpj_nt <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_rtpj_nt, REML=FALSE)
model_ltpj_nt <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_ltpj_nt, REML=FALSE)
model_pc_nt <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_pc_nt, REML=FALSE)
model_dmpfc_nt <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_dmpfc_nt, REML=FALSE)

rTPJ

# test pairwise contrasts
lsmeans(model_rtpj_nt, pairwise ~ Violation)
$lsmeans
 Violation lsmean      SE    df lower.CL upper.CL
 PH        0.2007 0.05077 42.85 0.098307   0.3031
 PS        0.2216 0.05077 42.85 0.119200   0.3240
 N         0.1084 0.05077 42.85 0.006032   0.2108

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE    df t.ratio p.value
 PH - PS  -0.02089 0.04785 35.72  -0.437  0.9005
 PH - N    0.09228 0.04785 35.72   1.929  0.1454
 PS - N    0.11317 0.04785 35.72   2.365  0.0597

P value adjustment: tukey method for comparing a family of 3 estimates 

lTPJ

# test pairwise contrasts
lsmeans(model_ltpj_nt, pairwise ~ Violation)
$lsmeans
 Violation lsmean      SE    df lower.CL upper.CL
 PH        0.2595 0.06081 39.21  0.13651   0.3824
 PS        0.2707 0.06081 39.20  0.14768   0.3936
 N         0.1401 0.06081 39.21  0.01711   0.2630

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE    df t.ratio p.value
 PH - PS  -0.01118 0.07468 35.54  -0.150  0.9877
 PH - N    0.11940 0.07468 35.55   1.599  0.2594
 PS - N    0.13058 0.07468 35.54   1.748  0.2017

P value adjustment: tukey method for comparing a family of 3 estimates 

precuneus

# test pairwise contrasts
lsmeans(model_pc_nt, pairwise ~ Violation)
$lsmeans
 Violation   lsmean      SE    df lower.CL upper.CL
 PH        -0.03654 0.04516 49.59 -0.12727  0.05419
 PS         0.03257 0.04516 49.59 -0.05817  0.12330
 N         -0.10693 0.04516 49.59 -0.19767 -0.01620

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE    df t.ratio p.value
 PH - PS   -0.0691 0.04934 35.44  -1.401  0.3514
 PH - N     0.0704 0.04934 35.44   1.427  0.3382
 PS - N     0.1395 0.04934 35.44   2.827  0.0204

P value adjustment: tukey method for comparing a family of 3 estimates 

dmPFC

# test pairwise contrasts
lsmeans(model_dmpfc_nt, pairwise ~ Violation)
$lsmeans
 Violation   lsmean      SE    df lower.CL upper.CL
 PH         0.04848 0.07077 33.34 -0.09544   0.1924
 PS         0.10088 0.07077 33.34 -0.04304   0.2448
 N         -0.03575 0.07077 33.34 -0.17967   0.1082

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE  df t.ratio p.value
 PH - PS  -0.05240 0.07065 513  -0.742  0.7387
 PH - N    0.08423 0.07065 513   1.192  0.4584
 PS - N    0.13663 0.07065 513   1.934  0.1302

P value adjustment: tukey method for comparing a family of 3 estimates 

ASD

Subset data to ASD group only and define model

data_asd <- subset(dat_psc_long, Group == "ASD")
model_asd <- lmer(PSC ~ 
                   Violation*ROI +
                   (1|Subject) + (1|Item), data=data_asd, REML=FALSE)
# model with slope of condition does not converge, so no comparison will be made between model w/ slope and model w/o slope.
# model_asd_1 <- lmer(PSC ~ 
#                      Violation*ROI +
#                      (Violation|Subject) + (1|Item), data=data_asd, REML=FALSE)

Test the condition x ROI interaction

anova(model_asd, update(model_asd, . ~ . - Violation:ROI))
Data: data_asd
Models:
update(model_asd, . ~ . - Violation:ROI): PSC ~ Violation + ROI + (1 | Subject) + (1 | Item)
model_asd: PSC ~ Violation * ROI + (1 | Subject) + (1 | Item)
                                         Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_asd, . ~ . - Violation:ROI)  9 3506 3556  -1744     3488                        
model_asd                                15 3517 3600  -1744     3487  0.85      6       0.99

Test the main effect of condition

anova(update(model_asd, . ~ . - Violation:ROI), update(model_asd, . ~ . - Violation:ROI - Violation))
Data: data_asd
Models:
update(model_asd, . ~ . - Violation:ROI - Violation): PSC ~ ROI + (1 | Subject) + (1 | Item)
update(model_asd, . ~ . - Violation:ROI): PSC ~ Violation + ROI + (1 | Subject) + (1 | Item)
                                                     Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)   
update(model_asd, . ~ . - Violation:ROI - Violation)  7 3513 3551  -1749     3499                           
update(model_asd, . ~ . - Violation:ROI)              9 3506 3556  -1744     3488  10.9      2     0.0042 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# test pairwise contrasts
lsmeans(model_asd, pairwise ~ Violation)
NOTE: Results may be misleading due to involvement in interactions
$lsmeans
 Violation  lsmean      SE    df lower.CL upper.CL
 PH        0.11668 0.03348 37.28  0.04886  0.18451
 PS        0.17087 0.03348 37.28  0.10304  0.23870
 N         0.02851 0.03348 37.28 -0.03932  0.09633

Results are averaged over the levels of: ROI 
Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE   df t.ratio p.value
 PH - PS  -0.05419 0.04062 39.6  -1.334  0.3852
 PH - N    0.08818 0.04062 39.6   2.171  0.0889
 PS - N    0.14237 0.04062 39.6   3.505  0.0032

Results are averaged over the levels of: ROI 
P value adjustment: tukey method for comparing a family of 3 estimates 

Figure: time course by condition for each ROI

dat_psc_orig$ROI <- factor(dat_psc_orig$ROI, levels=c("RTPJ", "LTPJ", "PC", "DMPFC"))
dat_psc_orig$Violation <- factor(dat_psc_orig$Violation, levels=c("PS", "PH", "N"))
dat_psc_asd <- dat_psc_orig%>% 
  filter(Group == 'ASD' & (Violation == 'PH' | Violation == 'PS' | Violation == 'N')) %>%
  group_by(Subject, Violation, ROI, Timepoint) %>%
  summarise(PSC=mean(PSC))
cols <- c("PS"="darkorchid4", "PH"="red", "N"="slategray")
rois <- c(RTPJ="rTPJ", LTPJ="lTPJ", PC="precuneus", DMPFC="dmPFC")
ggplot(dat_psc_asd, aes(y=PSC, x=Timepoint, color=Violation, fill=Violation)) +
  geom_smooth(na.rm=TRUE) +
  facet_wrap(~ROI, ncol=4, labeller=labeller(ROI=rois)) +
  annotate("rect", xmin=5, xmax=27, ymin=-Inf, ymax=Inf, alpha=.1) +
  scale_x_continuous(limits=c(0,28), breaks=seq(0,28,2)) +
  ylab("Percent signal change (PSC)") +
  xlab("Timepoint (s)") +
  scale_fill_manual(name="Condition\n", labels=c("Psychological harm", "Physical harm", "Neutral act"), values=cols) +
  scale_colour_manual(name="Condition\n", labels=c("Psychological harm", "Physical harm", "Neutral act"), values=cols) +
  theme_bw() +
  theme(axis.text=element_text(size=16),
        axis.title=element_text(size=24,face="bold"),
        axis.title.y=element_text(margin=margin(r=20)),
        axis.title.x=element_text(margin=margin(t=20)),
        legend.text=element_text(size=20),
        legend.title=element_text(size=24,face="bold"),
        legend.key.size=unit(3, "lines"),
        strip.text=element_text(size=28, face="bold"),
        panel.grid.major.x=element_blank(),
        panel.grid.major.y=element_blank())

Subset data by ROI (ASD only) and define models

dat_rtpj_asd <- subset(dat_psc_long, ROI == "RTPJ" & Group == "ASD")
dat_ltpj_asd <- subset(dat_psc_long, ROI == "LTPJ" & Group == "ASD")
dat_pc_asd <- subset(dat_psc_long, ROI == "PC" & Group == "ASD")
dat_dmpfc_asd <- subset(dat_psc_long, ROI == "DMPFC" & Group == "ASD")
model_rtpj_asd <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_rtpj_asd, REML=FALSE)
model_ltpj_asd <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_ltpj_asd, REML=FALSE)
model_pc_asd <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_pc_asd, REML=FALSE)
model_dmpfc_asd <- lmer(PSC ~ Violation + (1|Subject) + (1|Item),
                   dat=dat_dmpfc_asd, REML=FALSE)

rTPJ

# test pairwise contrasts
lsmeans(model_rtpj_asd, pairwise ~ Violation)
$lsmeans
 Violation  lsmean      SE    df lower.CL upper.CL
 PH        0.13685 0.06231 32.74  0.01003   0.2637
 PS        0.15947 0.06231 32.74  0.03266   0.2863
 N         0.04914 0.06231 32.74 -0.07767   0.1760

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate     SE    df t.ratio p.value
 PH - PS  -0.02263 0.0796 36.01  -0.284  0.9565
 PH - N    0.08770 0.0796 36.01   1.102  0.5192
 PS - N    0.11033 0.0796 36.01   1.386  0.3587

P value adjustment: tukey method for comparing a family of 3 estimates 

lTPJ

# test pairwise contrasts
lsmeans(model_ltpj_asd, pairwise ~ Violation)
$lsmeans
 Violation lsmean      SE    df lower.CL upper.CL
 PH        0.2884 0.08445 26.34  0.11496   0.4619
 PS        0.3231 0.08445 26.34  0.14960   0.4966
 N         0.1849 0.08445 26.34  0.01144   0.3584

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE  df t.ratio p.value
 PH - PS  -0.03464 0.08369 420  -0.414  0.9099
 PH - N    0.10352 0.08369 420   1.237  0.4321
 PS - N    0.13816 0.08369 420   1.651  0.2257

P value adjustment: tukey method for comparing a family of 3 estimates 

precuneus

# test pairwise contrasts
lsmeans(model_pc_asd, pairwise ~ Violation)
$lsmeans
 Violation    lsmean     SE    df  lower.CL upper.CL
 PH         0.006022 0.0449 27.86 -0.085982  0.09803
 PS         0.099761 0.0449 27.86  0.007757  0.19177
 N         -0.055337 0.0449 27.86 -0.147341  0.03667

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate      SE    df t.ratio p.value
 PH - PS  -0.09374 0.04262 34.72  -2.199  0.0854
 PH - N    0.06136 0.04262 34.72   1.440  0.3322
 PS - N    0.15510 0.04262 34.72   3.639  0.0025

P value adjustment: tukey method for comparing a family of 3 estimates 

dmPFC

# test pairwise contrasts
lsmeans(model_dmpfc_asd, pairwise ~ Violation)
$lsmeans
 Violation   lsmean      SE  df  lower.CL upper.CL
 PH         0.05501 0.06449 288 -0.071909  0.18194
 PS         0.12049 0.06449 288 -0.006437  0.24741
 N         -0.04427 0.06449 288 -0.171196  0.08265

Degrees-of-freedom method: satterthwaite 
Confidence level used: 0.95 

$contrasts
 contrast estimate     SE  df t.ratio p.value
 PH - PS  -0.06547 0.0912 288  -0.718  0.7531
 PH - N    0.09929 0.0912 288   1.089  0.5218
 PS - N    0.16476 0.0912 288   1.807  0.1692

P value adjustment: tukey method for comparing a family of 3 estimates 

NT vs ASD

Define the models

dat_rtpj <- subset(dat_psc_long, ROI == "RTPJ")
dat_ltpj <- subset(dat_psc_long, ROI == "LTPJ")
dat_pc <- subset(dat_psc_long, ROI == "PC")
dat_dmpfc <- subset(dat_psc_long, ROI == "DMPFC")
model_rtpj <- lmer(PSC ~ Violation*Group + (1|Subject) + (1|Item),
                   dat=dat_rtpj, REML=FALSE)
model_ltpj <- lmer(PSC ~ Violation*Group + (1|Subject) + (1|Item),
                   dat=dat_ltpj, REML=FALSE)
model_pc <- lmer(PSC ~ Violation*Group + (1|Subject) + (1|Item),
                   dat=dat_pc, REML=FALSE)
model_dmpfc <- lmer(PSC ~ Violation*Group + (1|Subject) + (1|Item),
                   dat=dat_dmpfc, REML=FALSE)
model_nt_vs_asd <- lmer(PSC ~ Violation*Group*ROI + (1|Subject) + (1|Item),
                   dat=dat_psc_long, REML=FALSE)

Test interaction: Condition x Group x ROI

anova(update(model_nt_vs_asd, . ~ . -Violation:Group:ROI), update(model_nt_vs_asd, . ~ . -Violation:Group:ROI - Violation:Group))
Data: dat_psc_long
Models:
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group): PSC ~ Violation + Group + ROI + (1 | Subject) + (1 | Item) + 
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group):     Violation:ROI + Group:ROI
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI): PSC ~ Violation + Group + ROI + (1 | Subject) + (1 | Item) + 
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI):     Violation:Group + Violation:ROI + Group:ROI
                                                                       Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group) 19 9420 9544  -4691     9382                        
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI)                   21 9424 9561  -4691     9382  0.16      2       0.92

Test interaction: Condition x Group

anova(update(model_nt_vs_asd, . ~ . -Violation:Group:ROI), update(model_nt_vs_asd, . ~ . -Violation:Group:ROI - Violation:Group))
Data: dat_psc_long
Models:
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group): PSC ~ Violation + Group + ROI + (1 | Subject) + (1 | Item) + 
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group):     Violation:ROI + Group:ROI
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI): PSC ~ Violation + Group + ROI + (1 | Subject) + (1 | Item) + 
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI):     Violation:Group + Violation:ROI + Group:ROI
                                                                       Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group) 19 9420 9544  -4691     9382                        
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI)                   21 9424 9561  -4691     9382  0.16      2       0.92

Subset data by ROI

rTPJ

anova(model_rtpj, update(model_rtpj, . ~ . -Violation:Group))
Data: dat_rtpj
Models:
update(model_rtpj, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
model_rtpj: PSC ~ Violation * Group + (1 | Subject) + (1 | Item)
                                            Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_rtpj, . ~ . - Violation:Group)  7 2415 2452  -1201     2401                        
model_rtpj                                   9 2419 2466  -1201     2401     0      2          1

lTPJ

anova(model_ltpj, update(model_ltpj, . ~ . -Violation:Group))
Data: dat_ltpj
Models:
update(model_ltpj, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
model_ltpj: PSC ~ Violation * Group + (1 | Subject) + (1 | Item)
                                            Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_ltpj, . ~ . - Violation:Group)  7 3095 3131  -1541     3081                        
model_ltpj                                   9 3099 3145  -1541     3081  0.04      2       0.98

precuneus

anova(model_pc, update(model_pc, . ~ . -Violation:Group))
Data: dat_pc
Models:
update(model_pc, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
model_pc: PSC ~ Violation * Group + (1 | Subject) + (1 | Item)
                                          Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_pc, . ~ . - Violation:Group)  7 1628 1665   -807     1614                        
model_pc                                   9 1631 1679   -807     1613  0.23      2       0.89

dmPFC

anova(model_dmpfc, update(model_dmpfc, . ~ . -Violation:Group))
Data: dat_dmpfc
Models:
update(model_dmpfc, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
model_dmpfc: PSC ~ Violation * Group + (1 | Subject) + (1 | Item)
                                             Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_dmpfc, . ~ . - Violation:Group)  7 1657 1690   -822     1643                        
model_dmpfc                                   9 1661 1704   -822     1643  0.06      2       0.97

Test main effect: Condition

anova(update(model_nt_vs_asd, . ~ . -Violation:Group:ROI -Violation:Group), update(model_nt_vs_asd, . ~ . -Violation:Group:ROI -Violation:Group -Violation))
Data: dat_psc_long
Models:
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group): PSC ~ Violation + Group + ROI + (1 | Subject) + (1 | Item) + 
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group):     Violation:ROI + Group:ROI
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group - Violation): PSC ~ Group + ROI + (1 | Subject) + (1 | Item) + Violation:ROI + 
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group - Violation):     Group:ROI
                                                                                   Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group)             19 9420 9544  -4691     9382                        
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group - Violation) 19 9420 9544  -4691     9382     0      0     <2e-16
                                                                                      
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group)                
update(model_nt_vs_asd, . ~ . - Violation:Group:ROI - Violation:Group - Violation) ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Subset data by ROI

rTPJ

anova(update(model_rtpj, . ~ . -Violation:Group), update(model_rtpj, . ~ . -Violation:Group -Violation))
Data: dat_rtpj
Models:
update(model_rtpj, . ~ . - Violation:Group - Violation): PSC ~ Group + (1 | Subject) + (1 | Item)
update(model_rtpj, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                        Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)  
update(model_rtpj, . ~ . - Violation:Group - Violation)  5 2419 2445  -1204     2409                          
update(model_rtpj, . ~ . - Violation:Group)              7 2415 2452  -1201     2401  7.38      2      0.025 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

lTPJ

anova(update(model_ltpj, . ~ . -Violation:Group), update(model_ltpj, . ~ . -Violation:Group -Violation))
Data: dat_ltpj
Models:
update(model_ltpj, . ~ . - Violation:Group - Violation): PSC ~ Group + (1 | Subject) + (1 | Item)
update(model_ltpj, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                        Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)  
update(model_ltpj, . ~ . - Violation:Group - Violation)  5 3097 3123  -1543     3087                          
update(model_ltpj, . ~ . - Violation:Group)              7 3095 3131  -1541     3081  5.71      2      0.058 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

precuneus

anova(update(model_pc, . ~ . -Violation:Group), update(model_pc, . ~ . -Violation:Group -Violation))
Data: dat_pc
Models:
update(model_pc, . ~ . - Violation:Group - Violation): PSC ~ Group + (1 | Subject) + (1 | Item)
update(model_pc, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                      Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)   
update(model_pc, . ~ . - Violation:Group - Violation)  5 1636 1663   -813     1626                           
update(model_pc, . ~ . - Violation:Group)              7 1628 1665   -807     1614  12.5      2     0.0019 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

dmPFC

anova(update(model_dmpfc, . ~ . -Violation:Group), update(model_dmpfc, . ~ . -Violation:Group -Violation))
Data: dat_dmpfc
Models:
update(model_dmpfc, . ~ . - Violation:Group - Violation): PSC ~ Group + (1 | Subject) + (1 | Item)
update(model_dmpfc, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                         Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)  
update(model_dmpfc, . ~ . - Violation:Group - Violation)  5 1660 1684   -825     1650                          
update(model_dmpfc, . ~ . - Violation:Group)              7 1657 1690   -822     1643  6.95      2      0.031 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Test main effect: Group

anova(update(model_nt_vs_asd, . ~ . -Violation:Group), update(model_nt_vs_asd, . ~ . -Violation:Group -Group))
Data: dat_psc_long
Models:
update(model_nt_vs_asd, . ~ . - Violation:Group): PSC ~ Violation + Group + ROI + (1 | Subject) + (1 | Item) + 
update(model_nt_vs_asd, . ~ . - Violation:Group):     Violation:ROI + Group:ROI + Violation:Group:ROI
update(model_nt_vs_asd, . ~ . - Violation:Group - Group): PSC ~ Violation + ROI + (1 | Subject) + (1 | Item) + Violation:ROI + 
update(model_nt_vs_asd, . ~ . - Violation:Group - Group):     Group:ROI + Violation:Group:ROI
                                                         Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)    
update(model_nt_vs_asd, . ~ . - Violation:Group)         27 9436 9612  -4691     9382                            
update(model_nt_vs_asd, . ~ . - Violation:Group - Group) 27 9436 9612  -4691     9382     0      0     <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Subset data by ROI

rTPJ

anova(update(model_rtpj, . ~ . -Violation:Group), update(model_rtpj, . ~ . -Violation:Group -Group))
Data: dat_rtpj
Models:
update(model_rtpj, . ~ . - Violation:Group - Group): PSC ~ Violation + (1 | Subject) + (1 | Item)
update(model_rtpj, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                    Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_rtpj, . ~ . - Violation:Group - Group)  6 2414 2446  -1201     2402                        
update(model_rtpj, . ~ . - Violation:Group)          7 2415 2452  -1201     2401  1.03      1       0.31

lTPJ

anova(update(model_ltpj, . ~ . -Violation:Group), update(model_ltpj, . ~ . -Violation:Group -Group))
Data: dat_ltpj
Models:
update(model_ltpj, . ~ . - Violation:Group - Group): PSC ~ Violation + (1 | Subject) + (1 | Item)
update(model_ltpj, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                    Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_ltpj, . ~ . - Violation:Group - Group)  6 3093 3124  -1541     3081                        
update(model_ltpj, . ~ . - Violation:Group)          7 3095 3131  -1541     3081   0.3      1       0.58

precuneus

anova(update(model_pc, . ~ . -Violation:Group), update(model_pc, . ~ . -Violation:Group -Group))
Data: dat_pc
Models:
update(model_pc, . ~ . - Violation:Group - Group): PSC ~ Violation + (1 | Subject) + (1 | Item)
update(model_pc, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                  Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_pc, . ~ . - Violation:Group - Group)  6 1627 1659   -807     1615                        
update(model_pc, . ~ . - Violation:Group)          7 1628 1665   -807     1614  1.16      1       0.28

dmPFC

anova(update(model_dmpfc, . ~ . -Violation:Group), update(model_dmpfc, . ~ . -Violation:Group -Group))
Data: dat_dmpfc
Models:
update(model_dmpfc, . ~ . - Violation:Group - Group): PSC ~ Violation + (1 | Subject) + (1 | Item)
update(model_dmpfc, . ~ . - Violation:Group): PSC ~ Violation + Group + (1 | Subject) + (1 | Item)
                                                     Df  AIC  BIC logLik deviance Chisq Chi Df Pr(>Chisq)
update(model_dmpfc, . ~ . - Violation:Group - Group)  6 1655 1684   -822     1643                        
update(model_dmpfc, . ~ . - Violation:Group)          7 1657 1690   -822     1643     0      1       0.95

ROI-based MVPA results

Data organization

# transform data to long format
dat_mvpa_long <- dat_mvpa_orig %>%
  gather(cond, acc, which(regexpr("_", colnames(.)) > 0)) %>%
  separate(cond, c("roi", "type"), extra="drop")

Comparing mean accuracies to chance (50%)

mvpa_res <- matrix(nrow=0, ncol=6,
                   dimnames=list(NULL, c("group","col", "t", "df", "p.value", "estimate")))
groups <- levels(dat_mvpa_orig$group)
for (cl in 3:ncol(dat_mvpa_orig)) {
  for (grp in groups) {
    temp <- dat_mvpa_orig[dat_mvpa_orig$group == grp, cl]
    mvpa_res <- rbind(mvpa_res, c(grp, colnames(dat_mvpa_orig)[cl],
                                  unlist(t.test(temp, mu=.5, alternative="greater"))[c(1, 2, 3, 6)]))
  }
}
# tidy up results
mvpa_res <- tidy(mvpa_res)
mvpa_res[,3:6] <- lapply(mvpa_res[,3:6], function(x) as.numeric(as.character(x)))
mvpa_res

Comparing mean accuracies of experimental tests vs. permutation tests

mvpa_res_exp_vs_perm <- matrix(nrow=0, ncol=8,
                               dimnames=list(NULL, c("group","col1", "col2", "t", "df", "p.value", "estimate.of.exp","estimate.of.perm")))
groups <- levels(dat_mvpa_orig$group)
for (cl in seq(3, ncol(dat_mvpa_orig), by=2)) {
  for (grp in groups) {
    temp1 <- dat_mvpa_orig[dat_mvpa_orig$group == grp, cl]
    temp2 <- dat_mvpa_orig[dat_mvpa_orig$group == grp, cl+1]
    mvpa_res_exp_vs_perm <- rbind(mvpa_res_exp_vs_perm, c(grp, colnames(dat_mvpa_orig)[cl], colnames(dat_mvpa_orig)[cl + 1],
                                                          unlist(t.test(temp1, temp2, alternative="greater"))[c(1, 2, 3, 6, 7)]))
  }
}
# tidy up results
mvpa_res_exp_vs_perm <- tidy(mvpa_res_exp_vs_perm)
mvpa_res_exp_vs_perm[,4:8] <- lapply(mvpa_res_exp_vs_perm[,4:8], function(x) as.numeric(as.character(x)))
mvpa_res_exp_vs_perm

Comparing mean accuracies of NT group vs. ASD group

mvpa_res_nt_vs_asd <- matrix(nrow=0, ncol=6,
                             dimnames=list(NULL, c("col", "t", "df", "p.value", "estimate of NT", "estimate of ASD")))
groups <- levels(dat_mvpa_orig$group)
for (cl in 3:ncol(dat_mvpa_orig)) {
  temp1 <- dat_mvpa_orig[dat_mvpa_orig$group == 'NT', cl]
  temp2 <- dat_mvpa_orig[dat_mvpa_orig$group == 'ASD', cl]
  mvpa_res_nt_vs_asd <- rbind(mvpa_res_nt_vs_asd, c(colnames(dat_mvpa_orig)[cl],
                                                    unlist(t.test(temp1, temp2, alternative="two.sided"))[c(1, 2, 3, 6, 7)]))
}
# tidy up results
mvpa_res_nt_vs_asd <- tidy(mvpa_res_nt_vs_asd)
mvpa_res_nt_vs_asd[,2:6] <- lapply(mvpa_res_nt_vs_asd[,2:6], function(x) as.numeric(as.character(x)))
mvpa_res_nt_vs_asd

Figure: classification accuracies

dat_mvpa_plot <- dat_mvpa_long
dat_mvpa_plot$roi <- factor(dat_mvpa_plot$roi, levels=c("RTPJ", "LTPJ", "PC", "DMPFC"))
dat_mvpa_plot$group <- factor(dat_mvpa_plot$group, levels=c("NT", "ASD"))
ggplot(dat_mvpa_plot, aes(y=acc, x=type)) +
  stat_summary(fun.data="mean_cl_boot", position=position_dodge(0.4)) +
  facet_grid(group ~ roi, labeller=labeller(roi=c(RTPJ="rTPJ", LTPJ="lTPJ", PC="precuneus", DMPFC="dmPFC"))) +
  geom_hline(yintercept=.50) +
  ylab("Classification accuracy") +
  scale_x_discrete("Test type\n", labels=c("exp"="Experimental", "perm"="Permutation")) + 
  theme_bw() +
  theme(axis.text=element_text(size=14),
        axis.title=element_text(size=16,face="bold"),
        axis.title.y=element_text(margin=margin(r=20)),
        axis.title.x=element_text(margin=margin(t=20)),
        strip.text=element_text(size=16, face="bold"),
        panel.grid.major.x=element_blank(),
        panel.grid.major.y=element_blank())

LS0tCnRpdGxlOiAiQmVoYXZpb3JhbCBhbmQgUk9JLWJhc2VkIGFuYWx5c2VzIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OiB5ZXMKZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiJUIgJWQsICVZIilgJwpwYXJhbXM6CiAgZGlyZWN0b3J5OiB+L0Rlc2t0b3AKLS0tCgpgYGB7ciBnbG9iYWxfb3B0aW9uc30Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UpCm9wdGlvbnMoc2NpcGVuPTAsIGRpZ2l0cz00KQpgYGAKCiMgSW50cm9kdWN0aW9uCgpCZWxvdyBhcmUgY29kZSBhbmQgb3V0cHV0cyBmb3IgdGhlIFJPSS1iYXNlZCBhbmFseXNlcyBpbiB0aGUgc3VibWl0dGVkIG1hbnVzY3JpcHQ6ICJOZXVyYWwgc3Vic3RyYXRlcyBmb3IgbW9yYWwganVkZ21lbnRzIG9mIHBzeWNob2xvZ2ljYWwgdmVyc3VzIHBoeXNpY2FsIGhhcm0iLgoKVG8gc2VlIGxhcmdlciB2ZXJzaW9ucyBvZiBhbnkgZmlndXJlLCByaWdodC1jbGljaywgY29weSBpbWFnZSBsb2NhdGlvbiwgYW5kIHBhc3RlIHRoZSBhZGRyZXNzIHRvIGEgbmV3IHRhYiBvbiB5b3VyIGJyb3dzZXIuCgpJZiB5b3UgaGF2ZSBhbnkgcXVlc3Rpb25zIGFuZC9vciBjb21tZW50cywgcGxlYXNlIGVtYWlsIExpbHkgVHNvaTogbGlseSBbZG90XSB0c29pIFthdF0gYmMgW2RvdF0gZWR1LiAKCiMgUGFja2FnZXMKCkluc3RhbGwgcGFja2FnZXMgYW5kIGxvYWQgbGlicmFyaWVzCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KcGFja2FnZXMgPC0gYygicm1hcmtkb3duIiwgImtuaXRyIiwgInRpZHl2ZXJzZSIsICJicm9vbSIsICJsbWU0IiwgIm9yZGluYWwiLCAibHNtZWFucyIpCnBhY2thZ2VzX25ldyA8LSBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLCJQYWNrYWdlIl0pXQppZihsZW5ndGgocGFja2FnZXNfbmV3KSkgaW5zdGFsbC5wYWNrYWdlcyhwYWNrYWdlc19uZXcpCmxhcHBseShwYWNrYWdlcyxsaWJyYXJ5LGNoYXJhY3Rlci5vbmx5PVQpCmBgYAoKIyBEYXRhIGltcG9ydAoKRGF0YSBmaWxlcyBjYW4gYmUgZm91bmQgb24gR2l0SHViOiBodHRwczovL2dpdGh1Yi5jb20vdHNvaWNlcy9wc3ljaC1waHlzLWhhcm0KCkFuYWx5c2VzIHJlcXVpcmUgdGhlIGZvbGxvd2luZyBmaWxlczoKCiogUFNZQ0gtUEhZU19ST0lfUFNDcy5jc3YKKiBST0lfbXZwYV9yZXN1bHRzLmNzdgoKTWFrZSBzdXJlIHRoZXNlIGZpbGVzIGFyZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuCgpgYGB7cn0KZmlsZXMgPC0gYygiUk9JX1BTQ3MuY3N2IiwgIlJPSV9NVlBBLmNzdiIpCgpkYXRfbmFtZXMgPC0gYygiZGF0X3BzY19vcmlnIiwgImRhdF9tdnBhX29yaWciKQoKZm9yKGkgaW4gMTpsZW5ndGgoZmlsZXMpKSB7CiAgYXNzaWduKGRhdF9uYW1lc1tpXSwgcmVhZC5jc3YocGFzdGUocGFyYW1zJGRpcmVjdG9yeSwgZmlsZXNbaV0sIHNlcD0nLycpKSkKfQoKIyBjaGFuZ2UgdGhlIG9yZGVyIG9mIGxldmVscwpkYXRfcHNjX29yaWckR3JvdXAgPC0gZmFjdG9yKGRhdF9wc2Nfb3JpZyRHcm91cCwgbGV2ZWxzPWMoIk5UIiwgIkFTRCIpKQpkYXRfcHNjX29yaWckVmlvbGF0aW9uIDwtIGZhY3RvcihkYXRfcHNjX29yaWckVmlvbGF0aW9uLCBsZXZlbHM9YygiUEgiLCAiUFMiLCAiTiIpKQpgYGAKCkFuYWx5c2VzIGFyZSBiYXNlZCBvbiB0aGUgZm9sbG93aW5nOgoKKiBOdW1iZXIgb2YgTlQgcGFydGljaXBhbnRzOiBgciBubGV2ZWxzKHVuaXF1ZShkcm9wbGV2ZWxzKGRhdF9wc2Nfb3JpZyRTdWJqZWN0W2RhdF9wc2Nfb3JpZyRHcm91cCA9PSAnTlQnXSkpKWAgCiogTnVtYmVyIG9mIEFTRCBwYXJ0aWNpcGFudHM6IGByIG5sZXZlbHModW5pcXVlKGRyb3BsZXZlbHMoZGF0X3BzY19vcmlnJFN1YmplY3RbZGF0X3BzY19vcmlnJEdyb3VwID09ICdBU0QnXSkpKWAKKiBOdW1iZXIgb2YgdG90YWwgcGFydGljaXBhbnRzOiBgciBubGV2ZWxzKGRhdF9wc2Nfb3JpZyRTdWJqZWN0KWAKCiMgQmVoYXZpb3JhbCByZXN1bHRzIHsudGFic2V0fQoKRXhhbWluaW5nIGJlaGF2aW9yYWwgcmVzcG9uc2VzIGluIHRoZSBzY2FubmVyCgoqIERWOiByYXRpbmcgKDEtNCkKKiBwcmVkaWN0b3JzOiBDb25kaXRpb24gKHBoeXNpY2FsLCBwc3ljaG9sb2dpY2FsLCBuZXV0cmFsKSwgR3JvdXAgKE5ULCBBU0QpCgoqKkRhdGEgb3JnYW5pemF0aW9uKioKCk9yZ2FuaXplIGJlaGF2aW9yYWwgZGF0YQoKYGBge3J9CiMgY2FsY3VsYXRlIG1lYW4gcmF0aW5nIGFzIHZhcmlhYmxlIG9uIHktYXhpcwpkYXRfYmVoYXYgPC0gZGF0X3BzY19vcmlnJT4lCiAgZmlsdGVyKFZpb2xhdGlvbiA9PSAnUEgnIHwgVmlvbGF0aW9uID09ICdQUycgfCBWaW9sYXRpb24gPT0gJ04nKSAlPiUKICBncm91cF9ieShTdWJqZWN0LCBWaW9sYXRpb24sIEdyb3VwLCBJdGVtLCBLZXkpICU+JQogIHN1bW1hcmlzZShtZWFuPW1lYW4oS2V5KSkgJT4lCiAgZHJvcGxldmVscy5kYXRhLmZyYW1lKC4pCgpkYXRfYmVoYXYkSXRlbSA8LSBtYXRjaChkYXRfYmVoYXYkSXRlbSwgdW5pcXVlKHNvcnQoZGF0X2JlaGF2JEl0ZW0pKSkgIyBvcmRlcmluZyBpdGVtcyBzdWNoIHRoYXQgaXQgZG9lc24ndCBjYXJlIGFib3V0IHB1cml0eSBpdGVtcwpgYGAKCiMjIFJhdGluZ3MgYnkgY29uZGl0aW9uIGFuZCBncm91cAoKYGBge3IsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTZ9CgpnZ3Bsb3QoZGF0X2JlaGF2LCBhZXMoeD1WaW9sYXRpb24sIHk9bWVhbiwgY29sb3I9VmlvbGF0aW9uKSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YT0ibWVhbl9jbF9ib290IiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoMC4yKSwgc2l6ZT0xKSArCiAgeWxpbSgxLDQpICsKICBmYWNldF93cmFwKH5Hcm91cCwgbmNvbD0yLCBsYWJlbGxlcj1sYWJlbGxlcihHcm91cD1jKE5UPSJOZXVyb3R5cGljYWwiLCBBU0Q9IkFTRCIpKSwgc2NhbGVzPSJmcmVlX3kiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygnUGh5c2ljYWwnLCdQc3ljaG9sb2dpY2FsJywgJ05ldXRyYWwnKSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iQ29uZGl0aW9uIiwgbGFiZWxzPWMoIlBoeXNpY2FsIiwgIlBzeWNob2xvZ2ljYWwiLCAiTmV1dHJhbCIpLCB2YWx1ZXM9YygicmVkIiwgImRhcmtvcmNoaWQ0IiwgInNsYXRlZ3JheSIpKSArCiAgeWxhYigiUmF0aW5nXG4oMT1ub3QgYXQgYWxsLCA0PXZlcnkpIikgKwogIHhsYWIoIkNvbmRpdGlvbiIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYsZmFjZT0iYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQobWFyZ2luPW1hcmdpbihyPTE4KSksCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKHQ9MTgpKSwKICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE4LGZhY2U9ImJvbGQiLCBtYXJnaW49bWFyZ2luKGI9MjApLCBoanVzdD0wLjUpLAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsZmFjZT0iYm9sZCIpLAogICAgICAgIHN0cmlwLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTQpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55PWVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyBSYXRpbmdzIGJ5IGl0ZW0gYW5kIGdyb3VwCgpgYGB7ciwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9Nn0KCmdncGxvdChkYXRfYmVoYXYsIGFlcyh5PW1lYW4sIHg9SXRlbSwgY29sb3I9VmlvbGF0aW9uKSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YT0ibWVhbl9jbF9ib290IiwgbmEucm09VFJVRSkgKwogIHlsaW0oMSw0KSArCiAgZmFjZXRfd3JhcCh+R3JvdXAsIG5jb2w9MiwgbGFiZWxsZXI9bGFiZWxsZXIoR3JvdXA9YyhOVD0iTmV1cm90eXBpY2FsIiwgQVNEPSJBU0QiKSksIHNjYWxlcz0iZnJlZV95IikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iQ29uZGl0aW9uIiwgbGFiZWxzPWMoIlBoeXNpY2FsIiwgIlBzeWNob2xvZ2ljYWwiLCAiTmV1dHJhbCIpLCB2YWx1ZXM9YygicmVkIiwgImRhcmtvcmNoaWQ0IiwgInNsYXRlZ3JheSIpKSArCiAgeWxhYigiUmF0aW5nXG4oMT1ub3QgYXQgYWxsLCA0PXZlcnkpIikgKwogIHhsYWIoIkl0ZW0iKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEyKSwKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2LGZhY2U9ImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KG1hcmdpbj1tYXJnaW4ocj0xOCkpLAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQobWFyZ2luPW1hcmdpbih0PTE4KSksCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJib2xkIiwgbWFyZ2luPW1hcmdpbihiPTIwKSwgaGp1c3Q9MC41KSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNCksCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0LGZhY2U9ImJvbGQiKSwKICAgICAgICBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueT1lbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMgQW5hbHlzZXMKCkRlZmluZSB0aGUgbW9kZWwKYGBge3J9CmRhdF9iZWhhdiRLZXkgPC0gZmFjdG9yKGRhdF9iZWhhdiRLZXkpCm1vZGVsX2JlaGF2IDwtIGNsbW0oS2V5IH4gVmlvbGF0aW9uKkdyb3VwICsgKDF8U3ViamVjdCkgKyAoMXxJdGVtKSwgCiAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRfYmVoYXYsCiAgICAgICAgICAgICAgICAgICAgbGluaz0icHJvYml0IiwKICAgICAgICAgICAgICAgICAgICBuYS5hY3Rpb249bmEub21pdCkKYGBgCgpUZXN0IGludGVyYWN0aW9uIGJldHdlZW4gR3JvdXAgYW5kIENvbmRpdGlvbgoKYGBge3J9CmFub3ZhKG1vZGVsX2JlaGF2LCB1cGRhdGUobW9kZWxfYmVoYXYsIC4gfiAuIC1WaW9sYXRpb246R3JvdXApKQpgYGAKClRlc3QgbWFpbiBlZmZlY3Qgb2YgY29uZGl0aW9uCgpgYGB7cn0KYW5vdmEodXBkYXRlKG1vZGVsX2JlaGF2LCAuIH4gLiAtIFZpb2xhdGlvbjpHcm91cCksIHVwZGF0ZShtb2RlbF9iZWhhdiwgLiB+IC4gLSBWaW9sYXRpb246R3JvdXAgLSBWaW9sYXRpb24pKQoKbHNtZWFucyhtb2RlbF9iZWhhdiwgcGFpcndpc2UgfiBWaW9sYXRpb24pCgpgYGAKCiMgUk9JLWJhc2VkIHVuaXZhcmlhdGUgcmVzdWx0cwoKKipEYXRhIG9yZ2FuaXphdGlvbioqCgpBbmFseXNlcyBkZXNjcmliZWQgaGVyZSBhcmUgb3ZlciB0aGUgZW50aXJlIHRpbWUgY291cnNlLiBGdXR1cmUgdmVyc2lvbnMgb2YgdGhpcyBkb2N1bWVudCB3aWxsIGxldCB5b3Ugc2VsZWN0IGEgdGltZSB3aW5kb3cgYW5kIGF1dG9tYXRpY2FsbHkgcmVmcmVzaCB0aGUgb3V0cHV0cyByZWxhdGVkIHRvIHRoYXQgdGltZSB3aW5kb3cuCgpUaW1lIHBvaW50cyBvZiBpbnRlcmVzdCAoc2Vjb25kcyk6CgoqIGVudGlyZSB0aW1lIGNvdXJzZTogICAgICAgNi0yNgoqIGJhY2tncm91bmQ6ICAgICAgICAgICAgICAgNi0xMAoqIGFjdGlvbjogICAgICAgICAgICAgICAgICAgMTItMTQKKiBvdXRjb21lOiAgICAgICAgICAgICAgICAgIDE2LTE4CiogaW50ZW50OiAgICAgICAgICAgICAgICAgICAyMC0yMgoqIGp1ZGdtZW50OiAgICAgICAgICAgICAgICAgMjQtMjYKCgpgYGB7cn0KdGltZV9lbnRpcmUgPC0gZGF0X3BzY19vcmlnICU+JSBmaWx0ZXIoVGltZXBvaW50ID49IDYgJiBUaW1lcG9pbnQgPD0gMjYpCnRpbWVfYmFja2dyb3VuZCA8LSBkYXRfcHNjX29yaWcgJT4lIGZpbHRlcihUaW1lcG9pbnQgPj0gNiAmIFRpbWVwb2ludCA8PSAxMCkKdGltZV9hY3Rpb24gPC0gZGF0X3BzY19vcmlnICU+JSBmaWx0ZXIoVGltZXBvaW50ID49IDEyICYgVGltZXBvaW50IDw9IDE0KQp0aW1lX291dGNvbWUgPC0gZGF0X3BzY19vcmlnICU+JSBmaWx0ZXIoVGltZXBvaW50ID49IDE2ICYgVGltZXBvaW50IDw9IDE4KQp0aW1lX2ludGVudCA8LSBkYXRfcHNjX29yaWcgJT4lIGZpbHRlcihUaW1lcG9pbnQgPj0gMjAgJiBUaW1lcG9pbnQgPD0gMjIpCnRpbWVfanVkZ21lbnQgPC0gZGF0X3BzY19vcmlnICU+JSBmaWx0ZXIoVGltZXBvaW50ID49IDI0ICYgVGltZXBvaW50IDw9IDI2KQoKZGF0X3BzY19sb25nIDwtIAogIHRpbWVfZW50aXJlICU+JSAKICBmaWx0ZXIoVmlvbGF0aW9uID09ICdQSCcgfCBWaW9sYXRpb24gPT0gJ1BTJyB8IFZpb2xhdGlvbiA9PSAnTicpICU+JQogIGdyb3VwX2J5KFN1YmplY3QsIFZpb2xhdGlvbiwgUk9JLCBHcm91cCwgSXRlbSwgS2V5KSAlPiUKICBzdW1tYXJpc2UoUFNDPW1lYW4oUFNDKSkgJT4lCiAgZHJvcGxldmVscy5kYXRhLmZyYW1lKC4pCgpkYXRfcHNjX2xvbmckSXRlbSA8LSBhcy5mYWN0b3IoZGF0X3BzY19sb25nJEl0ZW0pCgpgYGAKCiMjIE5UCgpTdWJzZXQgZGF0YSB0byBOVCBncm91cCBvbmx5IGFuZCBkZWZpbmUgbW9kZWwKCmBgYHtyfQpkYXRhX250IDwtIHN1YnNldChkYXRfcHNjX2xvbmcsIEdyb3VwID09ICJOVCIpCgptb2RlbF9udCA8LSBsbWVyKFBTQyB+IAogICAgICAgICAgICAgICAgICAgVmlvbGF0aW9uKlJPSSArCiAgICAgICAgICAgICAgICAgICAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLCBkYXRhPWRhdGFfbnQsIFJFTUw9RkFMU0UpCm1vZGVsX250XzEgPC0gbG1lcihQU0MgfiAKICAgICAgICAgICAgICAgICAgICAgVmlvbGF0aW9uKlJPSSArCiAgICAgICAgICAgICAgICAgICAgIChWaW9sYXRpb258U3ViamVjdCkgKyAoMXxJdGVtKSwgZGF0YT1kYXRhX250LCBSRU1MPUZBTFNFKQpgYGAKClRlc3QgdGhlIGNvbmRpdGlvbiB4IFJPSSBpbnRlcmFjdGlvbgoKYGBge3J9CmFub3ZhKG1vZGVsX250LCB1cGRhdGUobW9kZWxfbnQsIC4gfiAuIC0gVmlvbGF0aW9uOlJPSSkpCmBgYAoKVGVzdCB0aGUgbWFpbiBlZmZlY3Qgb2YgY29uZGl0aW9uCgpgYGB7cn0KYW5vdmEodXBkYXRlKG1vZGVsX250LCAuIH4gLiAtIFZpb2xhdGlvbjpST0kpLCB1cGRhdGUobW9kZWxfbnQsIC4gfiAuIC0gVmlvbGF0aW9uOlJPSSAtIFZpb2xhdGlvbikpCgojIHRlc3QgcGFpcndpc2UgY29udHJhc3RzCmxzbWVhbnMobW9kZWxfbnQsIHBhaXJ3aXNlIH4gVmlvbGF0aW9uKQpgYGAKClRlc3Qgd2hldGhlciBpbmNsdWRpbmcgcmFuZG9tIHNsb3BlIG9mIGNvbmRpdGlvbiBpbXByb3ZlcyBtb2RlbAoKYGBge3IsIGVjaG89VFJVRX0KYW5vdmEobW9kZWxfbnQsIG1vZGVsX250XzEpCmBgYAoKRmlndXJlOiB0aW1lIGNvdXJzZSBmb3IgZWFjaCBjb25kaXRpb24gYnkgUk9JCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTJ9CmRhdF9wc2Nfb3JpZyRST0kgPC0gZmFjdG9yKGRhdF9wc2Nfb3JpZyRST0ksIGxldmVscz1jKCJSVFBKIiwgIkxUUEoiLCAiUEMiLCAiRE1QRkMiKSkKZGF0X3BzY19vcmlnJFZpb2xhdGlvbiA8LSBmYWN0b3IoZGF0X3BzY19vcmlnJFZpb2xhdGlvbiwgbGV2ZWxzPWMoIlBTIiwgIlBIIiwgIk4iKSkKZGF0X3BzY19udCA8LSBkYXRfcHNjX29yaWclPiUgCiAgZmlsdGVyKEdyb3VwID09ICdOVCcgJiAoVmlvbGF0aW9uID09ICdQSCcgfCBWaW9sYXRpb24gPT0gJ1BTJyB8IFZpb2xhdGlvbiA9PSAnTicpKSAlPiUKICBncm91cF9ieShTdWJqZWN0LCBWaW9sYXRpb24sIFJPSSwgVGltZXBvaW50KSAlPiUKICBzdW1tYXJpc2UoUFNDPW1lYW4oUFNDKSkKY29scyA8LSBjKCJQUyI9ImRhcmtvcmNoaWQ0IiwgIlBIIj0icmVkIiwgIk4iPSJzbGF0ZWdyYXkiKQpyb2lzIDwtIGMoUlRQSj0iclRQSiIsIExUUEo9ImxUUEoiLCBQQz0icHJlY3VuZXVzIiwgRE1QRkM9ImRtUEZDIikKCmdncGxvdChkYXRfcHNjX250LCBhZXMoeT1QU0MsIHg9VGltZXBvaW50LCBjb2xvcj1WaW9sYXRpb24sIGZpbGw9VmlvbGF0aW9uKSkgKwogIGdlb21fc21vb3RoKG5hLnJtPVRSVUUpICsKICBmYWNldF93cmFwKH5ST0ksIG5jb2w9NCwgbGFiZWxsZXI9bGFiZWxsZXIoUk9JPXJvaXMpKSArCiAgYW5ub3RhdGUoInJlY3QiLCB4bWluPTUsIHhtYXg9MjcsIHltaW49LUluZiwgeW1heD1JbmYsIGFscGhhPS4xKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDAsMjgpLCBicmVha3M9c2VxKDAsMjgsMikpICsKICB5bGFiKCJQZXJjZW50IHNpZ25hbCBjaGFuZ2UgKFBTQykiKSArCiAgeGxhYigiVGltZXBvaW50IChzKSIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb25kaXRpb25cbiIsIGxhYmVscz1jKCJQc3ljaG9sb2dpY2FsIGhhcm0iLCAiUGh5c2ljYWwgaGFybSIsICJOZXV0cmFsIGFjdCIpLCB2YWx1ZXM9Y29scykgKwogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iQ29uZGl0aW9uXG4iLCBsYWJlbHM9YygiUHN5Y2hvbG9naWNhbCBoYXJtIiwgIlBoeXNpY2FsIGhhcm0iLCAiTmV1dHJhbCBhY3QiKSwgdmFsdWVzPWNvbHMpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjQsZmFjZT0iYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQobWFyZ2luPW1hcmdpbihyPTIwKSksCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKHQ9MjApKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTI0LGZhY2U9ImJvbGQiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgzLCAibGluZXMiKSwKICAgICAgICBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTI4LCBmYWNlPSJib2xkIiksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnk9ZWxlbWVudF9ibGFuaygpKQpgYGAKClN1YnNldCBkYXRhIGJ5IFJPSSAoTlQgb25seSkgYW5kIGRlZmluZSBtb2RlbHMKYGBge3J9CmRhdF9ydHBqX250IDwtIHN1YnNldChkYXRfcHNjX2xvbmcsIFJPSSA9PSAiUlRQSiIgJiBHcm91cCA9PSAiTlQiKQpkYXRfbHRwal9udCA8LSBzdWJzZXQoZGF0X3BzY19sb25nLCBST0kgPT0gIkxUUEoiICYgR3JvdXAgPT0gIk5UIikKZGF0X3BjX250IDwtIHN1YnNldChkYXRfcHNjX2xvbmcsIFJPSSA9PSAiUEMiICYgR3JvdXAgPT0gIk5UIikKZGF0X2RtcGZjX250IDwtIHN1YnNldChkYXRfcHNjX2xvbmcsIFJPSSA9PSAiRE1QRkMiICYgR3JvdXAgPT0gIk5UIikKCm1vZGVsX3J0cGpfbnQgPC0gbG1lcihQU0MgfiBWaW9sYXRpb24gKyAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLAogICAgICAgICAgICAgICAgICAgZGF0PWRhdF9ydHBqX250LCBSRU1MPUZBTFNFKQptb2RlbF9sdHBqX250IDwtIGxtZXIoUFNDIH4gVmlvbGF0aW9uICsgKDF8U3ViamVjdCkgKyAoMXxJdGVtKSwKICAgICAgICAgICAgICAgICAgIGRhdD1kYXRfbHRwal9udCwgUkVNTD1GQUxTRSkKbW9kZWxfcGNfbnQgPC0gbG1lcihQU0MgfiBWaW9sYXRpb24gKyAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLAogICAgICAgICAgICAgICAgICAgZGF0PWRhdF9wY19udCwgUkVNTD1GQUxTRSkKbW9kZWxfZG1wZmNfbnQgPC0gbG1lcihQU0MgfiBWaW9sYXRpb24gKyAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLAogICAgICAgICAgICAgICAgICAgZGF0PWRhdF9kbXBmY19udCwgUkVNTD1GQUxTRSkKYGBgCgoqKnJUUEoqKgoKYGBge3J9CiMgdGVzdCBwYWlyd2lzZSBjb250cmFzdHMKbHNtZWFucyhtb2RlbF9ydHBqX250LCBwYWlyd2lzZSB+IFZpb2xhdGlvbikKYGBgCgoqKmxUUEoqKgoKYGBge3J9CiMgdGVzdCBwYWlyd2lzZSBjb250cmFzdHMKbHNtZWFucyhtb2RlbF9sdHBqX250LCBwYWlyd2lzZSB+IFZpb2xhdGlvbikKYGBgCgoqKnByZWN1bmV1cyoqCgpgYGB7cn0KIyB0ZXN0IHBhaXJ3aXNlIGNvbnRyYXN0cwpsc21lYW5zKG1vZGVsX3BjX250LCBwYWlyd2lzZSB+IFZpb2xhdGlvbikKYGBgCgoqKmRtUEZDKioKCmBgYHtyfQojIHRlc3QgcGFpcndpc2UgY29udHJhc3RzCmxzbWVhbnMobW9kZWxfZG1wZmNfbnQsIHBhaXJ3aXNlIH4gVmlvbGF0aW9uKQpgYGAKCgojIyBBU0QKClN1YnNldCBkYXRhIHRvIEFTRCBncm91cCBvbmx5IGFuZCBkZWZpbmUgbW9kZWwKCmBgYHtyfQpkYXRhX2FzZCA8LSBzdWJzZXQoZGF0X3BzY19sb25nLCBHcm91cCA9PSAiQVNEIikKCm1vZGVsX2FzZCA8LSBsbWVyKFBTQyB+IAogICAgICAgICAgICAgICAgICAgVmlvbGF0aW9uKlJPSSArCiAgICAgICAgICAgICAgICAgICAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLCBkYXRhPWRhdGFfYXNkLCBSRU1MPUZBTFNFKQoKIyBtb2RlbCB3aXRoIHNsb3BlIG9mIGNvbmRpdGlvbiBkb2VzIG5vdCBjb252ZXJnZSwgc28gbm8gY29tcGFyaXNvbiB3aWxsIGJlIG1hZGUgYmV0d2VlbiBtb2RlbCB3LyBzbG9wZSBhbmQgbW9kZWwgdy9vIHNsb3BlLgojIG1vZGVsX2FzZF8xIDwtIGxtZXIoUFNDIH4gCiMgICAgICAgICAgICAgICAgICAgICAgVmlvbGF0aW9uKlJPSSArCiMgICAgICAgICAgICAgICAgICAgICAgKFZpb2xhdGlvbnxTdWJqZWN0KSArICgxfEl0ZW0pLCBkYXRhPWRhdGFfYXNkLCBSRU1MPUZBTFNFKQpgYGAKClRlc3QgdGhlIGNvbmRpdGlvbiB4IFJPSSBpbnRlcmFjdGlvbgoKYGBge3J9CmFub3ZhKG1vZGVsX2FzZCwgdXBkYXRlKG1vZGVsX2FzZCwgLiB+IC4gLSBWaW9sYXRpb246Uk9JKSkKYGBgCgpUZXN0IHRoZSBtYWluIGVmZmVjdCBvZiBjb25kaXRpb24KCmBgYHtyfQphbm92YSh1cGRhdGUobW9kZWxfYXNkLCAuIH4gLiAtIFZpb2xhdGlvbjpST0kpLCB1cGRhdGUobW9kZWxfYXNkLCAuIH4gLiAtIFZpb2xhdGlvbjpST0kgLSBWaW9sYXRpb24pKQoKIyB0ZXN0IHBhaXJ3aXNlIGNvbnRyYXN0cwpsc21lYW5zKG1vZGVsX2FzZCwgcGFpcndpc2UgfiBWaW9sYXRpb24pCmBgYAoKRmlndXJlOiB0aW1lIGNvdXJzZSBieSBjb25kaXRpb24gZm9yIGVhY2ggUk9JCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTJ9CmRhdF9wc2Nfb3JpZyRST0kgPC0gZmFjdG9yKGRhdF9wc2Nfb3JpZyRST0ksIGxldmVscz1jKCJSVFBKIiwgIkxUUEoiLCAiUEMiLCAiRE1QRkMiKSkKZGF0X3BzY19vcmlnJFZpb2xhdGlvbiA8LSBmYWN0b3IoZGF0X3BzY19vcmlnJFZpb2xhdGlvbiwgbGV2ZWxzPWMoIlBTIiwgIlBIIiwgIk4iKSkKZGF0X3BzY19hc2QgPC0gZGF0X3BzY19vcmlnJT4lIAogIGZpbHRlcihHcm91cCA9PSAnQVNEJyAmIChWaW9sYXRpb24gPT0gJ1BIJyB8IFZpb2xhdGlvbiA9PSAnUFMnIHwgVmlvbGF0aW9uID09ICdOJykpICU+JQogIGdyb3VwX2J5KFN1YmplY3QsIFZpb2xhdGlvbiwgUk9JLCBUaW1lcG9pbnQpICU+JQogIHN1bW1hcmlzZShQU0M9bWVhbihQU0MpKQpjb2xzIDwtIGMoIlBTIj0iZGFya29yY2hpZDQiLCAiUEgiPSJyZWQiLCAiTiI9InNsYXRlZ3JheSIpCnJvaXMgPC0gYyhSVFBKPSJyVFBKIiwgTFRQSj0ibFRQSiIsIFBDPSJwcmVjdW5ldXMiLCBETVBGQz0iZG1QRkMiKQoKZ2dwbG90KGRhdF9wc2NfYXNkLCBhZXMoeT1QU0MsIHg9VGltZXBvaW50LCBjb2xvcj1WaW9sYXRpb24sIGZpbGw9VmlvbGF0aW9uKSkgKwogIGdlb21fc21vb3RoKG5hLnJtPVRSVUUpICsKICBmYWNldF93cmFwKH5ST0ksIG5jb2w9NCwgbGFiZWxsZXI9bGFiZWxsZXIoUk9JPXJvaXMpKSArCiAgYW5ub3RhdGUoInJlY3QiLCB4bWluPTUsIHhtYXg9MjcsIHltaW49LUluZiwgeW1heD1JbmYsIGFscGhhPS4xKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDAsMjgpLCBicmVha3M9c2VxKDAsMjgsMikpICsKICB5bGFiKCJQZXJjZW50IHNpZ25hbCBjaGFuZ2UgKFBTQykiKSArCiAgeGxhYigiVGltZXBvaW50IChzKSIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb25kaXRpb25cbiIsIGxhYmVscz1jKCJQc3ljaG9sb2dpY2FsIGhhcm0iLCAiUGh5c2ljYWwgaGFybSIsICJOZXV0cmFsIGFjdCIpLCB2YWx1ZXM9Y29scykgKwogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iQ29uZGl0aW9uXG4iLCBsYWJlbHM9YygiUHN5Y2hvbG9naWNhbCBoYXJtIiwgIlBoeXNpY2FsIGhhcm0iLCAiTmV1dHJhbCBhY3QiKSwgdmFsdWVzPWNvbHMpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjQsZmFjZT0iYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQobWFyZ2luPW1hcmdpbihyPTIwKSksCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKHQ9MjApKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTI0LGZhY2U9ImJvbGQiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgzLCAibGluZXMiKSwKICAgICAgICBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTI4LCBmYWNlPSJib2xkIiksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnk9ZWxlbWVudF9ibGFuaygpKQpgYGAKClN1YnNldCBkYXRhIGJ5IFJPSSAoQVNEIG9ubHkpIGFuZCBkZWZpbmUgbW9kZWxzCmBgYHtyfQpkYXRfcnRwal9hc2QgPC0gc3Vic2V0KGRhdF9wc2NfbG9uZywgUk9JID09ICJSVFBKIiAmIEdyb3VwID09ICJBU0QiKQpkYXRfbHRwal9hc2QgPC0gc3Vic2V0KGRhdF9wc2NfbG9uZywgUk9JID09ICJMVFBKIiAmIEdyb3VwID09ICJBU0QiKQpkYXRfcGNfYXNkIDwtIHN1YnNldChkYXRfcHNjX2xvbmcsIFJPSSA9PSAiUEMiICYgR3JvdXAgPT0gIkFTRCIpCmRhdF9kbXBmY19hc2QgPC0gc3Vic2V0KGRhdF9wc2NfbG9uZywgUk9JID09ICJETVBGQyIgJiBHcm91cCA9PSAiQVNEIikKCm1vZGVsX3J0cGpfYXNkIDwtIGxtZXIoUFNDIH4gVmlvbGF0aW9uICsgKDF8U3ViamVjdCkgKyAoMXxJdGVtKSwKICAgICAgICAgICAgICAgICAgIGRhdD1kYXRfcnRwal9hc2QsIFJFTUw9RkFMU0UpCm1vZGVsX2x0cGpfYXNkIDwtIGxtZXIoUFNDIH4gVmlvbGF0aW9uICsgKDF8U3ViamVjdCkgKyAoMXxJdGVtKSwKICAgICAgICAgICAgICAgICAgIGRhdD1kYXRfbHRwal9hc2QsIFJFTUw9RkFMU0UpCm1vZGVsX3BjX2FzZCA8LSBsbWVyKFBTQyB+IFZpb2xhdGlvbiArICgxfFN1YmplY3QpICsgKDF8SXRlbSksCiAgICAgICAgICAgICAgICAgICBkYXQ9ZGF0X3BjX2FzZCwgUkVNTD1GQUxTRSkKbW9kZWxfZG1wZmNfYXNkIDwtIGxtZXIoUFNDIH4gVmlvbGF0aW9uICsgKDF8U3ViamVjdCkgKyAoMXxJdGVtKSwKICAgICAgICAgICAgICAgICAgIGRhdD1kYXRfZG1wZmNfYXNkLCBSRU1MPUZBTFNFKQpgYGAKCioqclRQSioqCgpgYGB7cn0KIyB0ZXN0IHBhaXJ3aXNlIGNvbnRyYXN0cwpsc21lYW5zKG1vZGVsX3J0cGpfYXNkLCBwYWlyd2lzZSB+IFZpb2xhdGlvbikKYGBgCgoqKmxUUEoqKgoKYGBge3J9CiMgdGVzdCBwYWlyd2lzZSBjb250cmFzdHMKbHNtZWFucyhtb2RlbF9sdHBqX2FzZCwgcGFpcndpc2UgfiBWaW9sYXRpb24pCmBgYAoKKipwcmVjdW5ldXMqKgoKYGBge3J9CiMgdGVzdCBwYWlyd2lzZSBjb250cmFzdHMKbHNtZWFucyhtb2RlbF9wY19hc2QsIHBhaXJ3aXNlIH4gVmlvbGF0aW9uKQpgYGAKCioqZG1QRkMqKgoKYGBge3J9CiMgdGVzdCBwYWlyd2lzZSBjb250cmFzdHMKbHNtZWFucyhtb2RlbF9kbXBmY19hc2QsIHBhaXJ3aXNlIH4gVmlvbGF0aW9uKQpgYGAKCgojIyBOVCB2cyBBU0QKCkRlZmluZSB0aGUgbW9kZWxzCmBgYHtyfQpkYXRfcnRwaiA8LSBzdWJzZXQoZGF0X3BzY19sb25nLCBST0kgPT0gIlJUUEoiKQpkYXRfbHRwaiA8LSBzdWJzZXQoZGF0X3BzY19sb25nLCBST0kgPT0gIkxUUEoiKQpkYXRfcGMgPC0gc3Vic2V0KGRhdF9wc2NfbG9uZywgUk9JID09ICJQQyIpCmRhdF9kbXBmYyA8LSBzdWJzZXQoZGF0X3BzY19sb25nLCBST0kgPT0gIkRNUEZDIikKCm1vZGVsX3J0cGogPC0gbG1lcihQU0MgfiBWaW9sYXRpb24qR3JvdXAgKyAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLAogICAgICAgICAgICAgICAgICAgZGF0PWRhdF9ydHBqLCBSRU1MPUZBTFNFKQptb2RlbF9sdHBqIDwtIGxtZXIoUFNDIH4gVmlvbGF0aW9uKkdyb3VwICsgKDF8U3ViamVjdCkgKyAoMXxJdGVtKSwKICAgICAgICAgICAgICAgICAgIGRhdD1kYXRfbHRwaiwgUkVNTD1GQUxTRSkKbW9kZWxfcGMgPC0gbG1lcihQU0MgfiBWaW9sYXRpb24qR3JvdXAgKyAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLAogICAgICAgICAgICAgICAgICAgZGF0PWRhdF9wYywgUkVNTD1GQUxTRSkKbW9kZWxfZG1wZmMgPC0gbG1lcihQU0MgfiBWaW9sYXRpb24qR3JvdXAgKyAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLAogICAgICAgICAgICAgICAgICAgZGF0PWRhdF9kbXBmYywgUkVNTD1GQUxTRSkKCm1vZGVsX250X3ZzX2FzZCA8LSBsbWVyKFBTQyB+IFZpb2xhdGlvbipHcm91cCpST0kgKyAoMXxTdWJqZWN0KSArICgxfEl0ZW0pLAogICAgICAgICAgICAgICAgICAgZGF0PWRhdF9wc2NfbG9uZywgUkVNTD1GQUxTRSkKYGBgCgoqKlRlc3QgaW50ZXJhY3Rpb246IENvbmRpdGlvbiB4IEdyb3VwIHggUk9JKioKCmBgYHtyfQphbm92YSh1cGRhdGUobW9kZWxfbnRfdnNfYXNkLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwOlJPSSksIHVwZGF0ZShtb2RlbF9udF92c19hc2QsIC4gfiAuIC1WaW9sYXRpb246R3JvdXA6Uk9JIC0gVmlvbGF0aW9uOkdyb3VwKSkKYGBgCgoqKlRlc3QgaW50ZXJhY3Rpb246IENvbmRpdGlvbiB4IEdyb3VwKioKCmBgYHtyfQphbm92YSh1cGRhdGUobW9kZWxfbnRfdnNfYXNkLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwOlJPSSksIHVwZGF0ZShtb2RlbF9udF92c19hc2QsIC4gfiAuIC1WaW9sYXRpb246R3JvdXA6Uk9JIC0gVmlvbGF0aW9uOkdyb3VwKSkKYGBgCgpTdWJzZXQgZGF0YSBieSBST0kKCioqclRQSioqCgpgYGB7cn0KYW5vdmEobW9kZWxfcnRwaiwgdXBkYXRlKG1vZGVsX3J0cGosIC4gfiAuIC1WaW9sYXRpb246R3JvdXApKQpgYGAKCioqbFRQSioqCgpgYGB7cn0KYW5vdmEobW9kZWxfbHRwaiwgdXBkYXRlKG1vZGVsX2x0cGosIC4gfiAuIC1WaW9sYXRpb246R3JvdXApKQpgYGAKCioqcHJlY3VuZXVzKioKCmBgYHtyfQphbm92YShtb2RlbF9wYywgdXBkYXRlKG1vZGVsX3BjLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwKSkKYGBgCgoqKmRtUEZDKioKCmBgYHtyfQphbm92YShtb2RlbF9kbXBmYywgdXBkYXRlKG1vZGVsX2RtcGZjLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwKSkKYGBgCgoqKlRlc3QgbWFpbiBlZmZlY3Q6IENvbmRpdGlvbioqCgoKYGBge3J9CmFub3ZhKHVwZGF0ZShtb2RlbF9udF92c19hc2QsIC4gfiAuIC1WaW9sYXRpb246R3JvdXA6Uk9JIC1WaW9sYXRpb246R3JvdXApLCB1cGRhdGUobW9kZWxfbnRfdnNfYXNkLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwOlJPSSAtVmlvbGF0aW9uOkdyb3VwIC1WaW9sYXRpb24pKQpgYGAKClN1YnNldCBkYXRhIGJ5IFJPSQoKKipyVFBKKioKCmBgYHtyfQphbm92YSh1cGRhdGUobW9kZWxfcnRwaiwgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCksIHVwZGF0ZShtb2RlbF9ydHBqLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwIC1WaW9sYXRpb24pKQpgYGAKCioqbFRQSioqCgpgYGB7cn0KYW5vdmEodXBkYXRlKG1vZGVsX2x0cGosIC4gfiAuIC1WaW9sYXRpb246R3JvdXApLCB1cGRhdGUobW9kZWxfbHRwaiwgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCAtVmlvbGF0aW9uKSkKYGBgCgoqKnByZWN1bmV1cyoqCgpgYGB7cn0KYW5vdmEodXBkYXRlKG1vZGVsX3BjLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwKSwgdXBkYXRlKG1vZGVsX3BjLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwIC1WaW9sYXRpb24pKQpgYGAKCioqZG1QRkMqKgoKYGBge3J9CmFub3ZhKHVwZGF0ZShtb2RlbF9kbXBmYywgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCksIHVwZGF0ZShtb2RlbF9kbXBmYywgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCAtVmlvbGF0aW9uKSkKYGBgCgoqKlRlc3QgbWFpbiBlZmZlY3Q6IEdyb3VwKioKCmBgYHtyfQphbm92YSh1cGRhdGUobW9kZWxfbnRfdnNfYXNkLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwKSwgdXBkYXRlKG1vZGVsX250X3ZzX2FzZCwgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCAtR3JvdXApKQpgYGAKClN1YnNldCBkYXRhIGJ5IFJPSQoKKipyVFBKKioKCmBgYHtyfQphbm92YSh1cGRhdGUobW9kZWxfcnRwaiwgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCksIHVwZGF0ZShtb2RlbF9ydHBqLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwIC1Hcm91cCkpCmBgYAoKKipsVFBKKioKCmBgYHtyfQphbm92YSh1cGRhdGUobW9kZWxfbHRwaiwgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCksIHVwZGF0ZShtb2RlbF9sdHBqLCAuIH4gLiAtVmlvbGF0aW9uOkdyb3VwIC1Hcm91cCkpCmBgYAoKKipwcmVjdW5ldXMqKgoKYGBge3J9CmFub3ZhKHVwZGF0ZShtb2RlbF9wYywgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCksIHVwZGF0ZShtb2RlbF9wYywgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCAtR3JvdXApKQpgYGAKCioqZG1QRkMqKgoKYGBge3J9CmFub3ZhKHVwZGF0ZShtb2RlbF9kbXBmYywgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCksIHVwZGF0ZShtb2RlbF9kbXBmYywgLiB+IC4gLVZpb2xhdGlvbjpHcm91cCAtR3JvdXApKQpgYGAKCiMgUk9JLWJhc2VkIE1WUEEgcmVzdWx0cwoKKipEYXRhIG9yZ2FuaXphdGlvbioqCgpgYGB7cn0KIyB0cmFuc2Zvcm0gZGF0YSB0byBsb25nIGZvcm1hdApkYXRfbXZwYV9sb25nIDwtIGRhdF9tdnBhX29yaWcgJT4lCiAgZ2F0aGVyKGNvbmQsIGFjYywgd2hpY2gocmVnZXhwcigiXyIsIGNvbG5hbWVzKC4pKSA+IDApKSAlPiUKICBzZXBhcmF0ZShjb25kLCBjKCJyb2kiLCAidHlwZSIpLCBleHRyYT0iZHJvcCIpCmBgYAoKCioqQ29tcGFyaW5nIG1lYW4gYWNjdXJhY2llcyB0byBjaGFuY2UgKDUwJSkqKgoKYGBge3IsIHJvd3MucHJpbnQ9MTZ9Cm12cGFfcmVzIDwtIG1hdHJpeChucm93PTAsIG5jb2w9NiwKICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzPWxpc3QoTlVMTCwgYygiZ3JvdXAiLCJjb2wiLCAidCIsICJkZiIsICJwLnZhbHVlIiwgImVzdGltYXRlIikpKQpncm91cHMgPC0gbGV2ZWxzKGRhdF9tdnBhX29yaWckZ3JvdXApCgpmb3IgKGNsIGluIDM6bmNvbChkYXRfbXZwYV9vcmlnKSkgewogIGZvciAoZ3JwIGluIGdyb3VwcykgewogICAgdGVtcCA8LSBkYXRfbXZwYV9vcmlnW2RhdF9tdnBhX29yaWckZ3JvdXAgPT0gZ3JwLCBjbF0KICAgIG12cGFfcmVzIDwtIHJiaW5kKG12cGFfcmVzLCBjKGdycCwgY29sbmFtZXMoZGF0X212cGFfb3JpZylbY2xdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5saXN0KHQudGVzdCh0ZW1wLCBtdT0uNSwgYWx0ZXJuYXRpdmU9ImdyZWF0ZXIiKSlbYygxLCAyLCAzLCA2KV0pKQogIH0KfQoKIyB0aWR5IHVwIHJlc3VsdHMKbXZwYV9yZXMgPC0gdGlkeShtdnBhX3JlcykKbXZwYV9yZXNbLDM6Nl0gPC0gbGFwcGx5KG12cGFfcmVzWywzOjZdLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSkpCgptdnBhX3JlcwpgYGAKCioqQ29tcGFyaW5nIG1lYW4gYWNjdXJhY2llcyBvZiBleHBlcmltZW50YWwgdGVzdHMgdnMuIHBlcm11dGF0aW9uIHRlc3RzKioKCmBgYHtyLCBjb2xzLnByaW50PTh9Cm12cGFfcmVzX2V4cF92c19wZXJtIDwtIG1hdHJpeChucm93PTAsIG5jb2w9OCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzPWxpc3QoTlVMTCwgYygiZ3JvdXAiLCJjb2wxIiwgImNvbDIiLCAidCIsICJkZiIsICJwLnZhbHVlIiwgImVzdGltYXRlLm9mLmV4cCIsImVzdGltYXRlLm9mLnBlcm0iKSkpCmdyb3VwcyA8LSBsZXZlbHMoZGF0X212cGFfb3JpZyRncm91cCkKCmZvciAoY2wgaW4gc2VxKDMsIG5jb2woZGF0X212cGFfb3JpZyksIGJ5PTIpKSB7CiAgZm9yIChncnAgaW4gZ3JvdXBzKSB7CiAgICB0ZW1wMSA8LSBkYXRfbXZwYV9vcmlnW2RhdF9tdnBhX29yaWckZ3JvdXAgPT0gZ3JwLCBjbF0KICAgIHRlbXAyIDwtIGRhdF9tdnBhX29yaWdbZGF0X212cGFfb3JpZyRncm91cCA9PSBncnAsIGNsKzFdCiAgICBtdnBhX3Jlc19leHBfdnNfcGVybSA8LSByYmluZChtdnBhX3Jlc19leHBfdnNfcGVybSwgYyhncnAsIGNvbG5hbWVzKGRhdF9tdnBhX29yaWcpW2NsXSwgY29sbmFtZXMoZGF0X212cGFfb3JpZylbY2wgKyAxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVubGlzdCh0LnRlc3QodGVtcDEsIHRlbXAyLCBhbHRlcm5hdGl2ZT0iZ3JlYXRlciIpKVtjKDEsIDIsIDMsIDYsIDcpXSkpCiAgfQp9CgojIHRpZHkgdXAgcmVzdWx0cwptdnBhX3Jlc19leHBfdnNfcGVybSA8LSB0aWR5KG12cGFfcmVzX2V4cF92c19wZXJtKQptdnBhX3Jlc19leHBfdnNfcGVybVssNDo4XSA8LSBsYXBwbHkobXZwYV9yZXNfZXhwX3ZzX3Blcm1bLDQ6OF0sIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKSkKCm12cGFfcmVzX2V4cF92c19wZXJtCmBgYAoKKipDb21wYXJpbmcgbWVhbiBhY2N1cmFjaWVzIG9mIE5UIGdyb3VwIHZzLiBBU0QgZ3JvdXAqKgoKYGBge3J9Cm12cGFfcmVzX250X3ZzX2FzZCA8LSBtYXRyaXgobnJvdz0wLCBuY29sPTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltbmFtZXM9bGlzdChOVUxMLCBjKCJjb2wiLCAidCIsICJkZiIsICJwLnZhbHVlIiwgImVzdGltYXRlIG9mIE5UIiwgImVzdGltYXRlIG9mIEFTRCIpKSkKZ3JvdXBzIDwtIGxldmVscyhkYXRfbXZwYV9vcmlnJGdyb3VwKQoKZm9yIChjbCBpbiAzOm5jb2woZGF0X212cGFfb3JpZykpIHsKICB0ZW1wMSA8LSBkYXRfbXZwYV9vcmlnW2RhdF9tdnBhX29yaWckZ3JvdXAgPT0gJ05UJywgY2xdCiAgdGVtcDIgPC0gZGF0X212cGFfb3JpZ1tkYXRfbXZwYV9vcmlnJGdyb3VwID09ICdBU0QnLCBjbF0KICBtdnBhX3Jlc19udF92c19hc2QgPC0gcmJpbmQobXZwYV9yZXNfbnRfdnNfYXNkLCBjKGNvbG5hbWVzKGRhdF9tdnBhX29yaWcpW2NsXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVubGlzdCh0LnRlc3QodGVtcDEsIHRlbXAyLCBhbHRlcm5hdGl2ZT0idHdvLnNpZGVkIikpW2MoMSwgMiwgMywgNiwgNyldKSkKfQoKIyB0aWR5IHVwIHJlc3VsdHMKbXZwYV9yZXNfbnRfdnNfYXNkIDwtIHRpZHkobXZwYV9yZXNfbnRfdnNfYXNkKQptdnBhX3Jlc19udF92c19hc2RbLDI6Nl0gPC0gbGFwcGx5KG12cGFfcmVzX250X3ZzX2FzZFssMjo2XSwgZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKQoKbXZwYV9yZXNfbnRfdnNfYXNkCgpgYGAKCkZpZ3VyZTogY2xhc3NpZmljYXRpb24gYWNjdXJhY2llcwoKYGBge3IsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTZ9CgpkYXRfbXZwYV9wbG90IDwtIGRhdF9tdnBhX2xvbmcKZGF0X212cGFfcGxvdCRyb2kgPC0gZmFjdG9yKGRhdF9tdnBhX3Bsb3Qkcm9pLCBsZXZlbHM9YygiUlRQSiIsICJMVFBKIiwgIlBDIiwgIkRNUEZDIikpCmRhdF9tdnBhX3Bsb3QkZ3JvdXAgPC0gZmFjdG9yKGRhdF9tdnBhX3Bsb3QkZ3JvdXAsIGxldmVscz1jKCJOVCIsICJBU0QiKSkKCmdncGxvdChkYXRfbXZwYV9wbG90LCBhZXMoeT1hY2MsIHg9dHlwZSkpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGE9Im1lYW5fY2xfYm9vdCIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuNCkpICsKICBmYWNldF9ncmlkKGdyb3VwIH4gcm9pLCBsYWJlbGxlcj1sYWJlbGxlcihyb2k9YyhSVFBKPSJyVFBKIiwgTFRQSj0ibFRQSiIsIFBDPSJwcmVjdW5ldXMiLCBETVBGQz0iZG1QRkMiKSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9LjUwKSArCiAgeWxhYigiQ2xhc3NpZmljYXRpb24gYWNjdXJhY3kiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgiVGVzdCB0eXBlXG4iLCBsYWJlbHM9YygiZXhwIj0iRXhwZXJpbWVudGFsIiwgInBlcm0iPSJQZXJtdXRhdGlvbiIpKSArIAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNCksCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNixmYWNlPSJib2xkIiksCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKHI9MjApKSwKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KG1hcmdpbj1tYXJnaW4odD0yMCkpLAogICAgICAgIHN0cmlwLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYsIGZhY2U9ImJvbGQiKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueT1lbGVtZW50X2JsYW5rKCkpCmBgYAo=